package matcher

import (
	"fmt"
	"go-regx/cmd"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"time"

	"gopkg.in/yaml.v3"
)

// MatcherInterface 定义 Matcher 的接口
type MatcherInterface interface {
	LoadRules(rulesPath string) error
	ProcessText() []Match_result
}

// Matcher 定义 Matcher 结构体
type Matcher struct {
	Rule_map  map[uint32]Rules
	Case_list []*TestCase
}

// NewMatcher 创建一个新的 Matcher 实例
func NewMatcher() *Matcher {
	return &Matcher{
		Rule_map:  make(map[uint32]Rules),
		Case_list: []*TestCase{},
	}
}

// LoadRules 加载规则
func (m *Matcher) LoadRules(rulesPath string) error {
	file_list, err := m.readDirectory(rulesPath)
	if err != nil {
		return err
	}
	for _, i := range file_list {
		var rules Rules
		data, err := os.ReadFile(i)
		if err != nil {
			return fmt.Errorf("无法读取配置文件%s: %v", i, err)
		}
		err = yaml.Unmarshal(data, &rules)
		if err != nil {
			return fmt.Errorf("解析 YAML 文件 %s 失败: %v", i, err)
		}
		if rules.RuleID == 0 {
			continue
		}
		for _, j := range rules.Detect.Reg {
			ok, buf := m.validateRegex(j)
			if ok == false {
				log.Printf("IN file %s error: %s ", i, buf)
			}
		}

		m.Rule_map[rules.RuleID] = rules
	}

	if cmd.Conf_arg.Verbose {
		for i, j := range m.Rule_map {
			log.Printf("rule key:%d value:%v", i, j)
		}
	}

	return nil
}

// ProcessText 处理文本
func (m *Matcher) ProcessText() []Match_result {
	var mr_list []Match_result
	compiledRules := m.compileRules()
	for _, re := range compiledRules {
		startTime := time.Now()
		HitCount := 0
		var hl []Hits_list
		var mr Match_result
		for _, i := range m.Case_list {
			matches := re.Regex.FindAllStringIndex(i.Text, -1)
			for _, match := range matches {
				HitCount++
				var hl_t Hits_list
				mc := mapCoords(i.Text, match)
				hl_t.HitContent = i.Text[match[0]:match[1]]
				hl_t.StartPosition = mc[0]
				hl_t.EndPosition = mc[1]
				hl_t.Context = Context_st{
					PreText:  i.Text[:match[0]],
					PostText: i.Text[match[1]:],
				}
				hl = append(hl, hl_t)
				for _, j := range i.Spans {
					if j.Label == re.Rule.RuleType {
						if j.Start == mc[0] && j.End == mc[1] {
							j.Priority = re.Rule.Priority
						} else {
							j.Rstart = mc[0]
							j.Rend = mc[1]
						}
					}
				}
			}
		}
		if hl == nil {
			continue
		}
		mr.DataType = re.Rule.RuleType
		mr.RuleID = re.Rule.RuleID
		mr.HitCount = HitCount
		mr.Hits = hl
		mr.Etime = time.Since(startTime)
		mr_list = append(mr_list, mr)
	}
	return mr_list
}

// compileRules 编译规则
func (m *Matcher) compileRules() []Rule_Regex {
	var compiledRules []Rule_Regex
	for _, i := range m.Rule_map {
		var combinedPattern string
		if len(i.Detect.Reg) > 1 {
			combinedPattern = "(" + i.Detect.Reg[0] + ")"
			for _, j := range i.Detect.Reg[1:] {
				combinedPattern += "|(" + j + ")"
			}
		} else {
			combinedPattern = i.Detect.Reg[0]
		}

		re := regexp.MustCompile(combinedPattern)
		compiledRules = append(compiledRules, Rule_Regex{Rule: i, Regex: re})
	}
	return compiledRules
}

// readDirectory 读取目录
func (m *Matcher) readDirectory(path string) ([]string, error) {
	var file_list []string
	err := filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("Error accessing path %q: %v", filePath, err)
		}

		if !info.IsDir() {
			file_list = append(file_list, filePath)
		}

		return nil
	})
	return file_list, err
}

// validateRegex 验证正则表达式
func (m *Matcher) validateRegex(pattern string) (bool, string) {
	_, err := regexp.Compile(pattern)
	if err != nil {
		return false, fmt.Sprintf("Invalid regex: %s\nError: %v\n", pattern, err)
	}
	return true, ""
}

// Match_result 匹配结果
type Match_result struct {
	RuleID   uint32 `json:"RuleID"`
	DataType string `json:"DataType"`
	HitCount int    `json:"HitCount"`
	Etime    time.Duration
	Hits     []Hits_list `json:"Hits"`
}

// Hits_list 匹配列表
type Hits_list struct {
	HitContent    string     `json:"HitContent"`
	StartPosition int        `json:"StartPosition"`
	EndPosition   int        `json:"EndPosition"`
	Context       Context_st `json:"Context"`
}

// Context_st 上下文
type Context_st struct {
	PreText  string `json:"PreText"`
	PostText string `json:"PostText"`
}

// Span 匹配范围
type Span struct {
	Label    string `json:"label"`
	Start    int    `json:"start"`
	End      int    `json:"end"`
	Rstart   int
	Rend     int
	Priority int
}

// TestCase 测试用例
type TestCase struct {
	Text  string  `json:"text"`
	Spans []*Span `json:"spans"`
}

// Rules 规则
type Rules struct {
	RuleID      uint32      `yaml:"RuleID"`
	RuleName    string      `yaml:"RuleName"`
	Description string      `yaml:"Description"`
	RuleType    string      `yaml:"RuleType"`
	Priority    int         `yaml:"Priority"`
	Version     string      `yaml:"Version"`
	Author      string      `yaml:"Author"`
	CreateDate  string      `yaml:"CreateDate"`
	UpdateDate  string      `yaml:"UpdateDate"`
	Detect      Rule_Detect `yaml:"Detect"`
}

// Rule_Detect 检测规则
type Rule_Detect struct {
	Reg []string `yaml:"Reg"`
}

// Rule_Regex 规则正则表达式
type Rule_Regex struct {
	Rule  Rules
	Regex *regexp.Regexp
}
